/*
 * Copyright (c) 2009, Luke Emrose
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.  Neither the name of Luke Emrose Sole Trader nor the
 * names of its contributors may be used to endorse or promote
 * products derived from this software without specific prior written
 * permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
 #include <iostream>

#include <rx.h>
#include <RslPlugin.h>

#include <OpenEXR/ImathVec.h>

#include "timestats.hpp"

#include "improvedPerlin.hpp"
#include "waveletNoise.hpp"
#include "voronoiNoise.hpp"

#define NUM_POINTS 10000000

int main( int argc, char* argv[] )
{
	bool show_result = false;

	std::vector< Imath::Vec3< float > > points( NUM_POINTS );
	std::vector< Imath::Vec3< float > >::iterator i;

	timestats timer;
	timer.restart();

	std::cout << "generating " << NUM_POINTS << " random points...." << std::endl;
	for( i = points.begin(); i != points.end(); ++i )
	{
		( *i ).x = 10000 * ( ( float ) rand() / ( float ) RAND_MAX );
		( *i ).y = 10000 * ( ( float ) rand() / ( float ) RAND_MAX );
		( *i ).z = 10000 * ( ( float ) rand() / ( float ) RAND_MAX );
	}
	std::cout << "finished generating the random points...." << std::endl;
	std::cout << timer.elapsed() << std::endl;

	timer.restart();
	std::cout << std::endl;

	std::cout << "starting non-sse2 noise...." << std::endl;
	for( i = points.begin(); i != points.end(); ++i )
	{
		float result = improvedNoise_impl< float >( *i );
		if( show_result ) { std::cout << result << std::endl; }
	}
	std::cout << "finished non-sse2 noise...." << std::endl;
	std::cout << timer.elapsed() << std::endl;

	timer.restart();
	std::cout << std::endl;

	std::cout << "starting non-sse2 fbm noise...." << std::endl;
	for( i = points.begin(); i != points.end(); ++i )
	{
		float result = improvedNoiseFBM_impl< float >( *i, 5, 2, 0.707f );
		if( show_result ) { std::cout << result << std::endl; }
	}
	std::cout << "finished non-sse2 fbm noise...." << std::endl;
	std::cout << timer.elapsed() << std::endl;

	timer.restart();
	std::cout << std::endl;

	std::cout << "starting sse2 noise...." << std::endl;
	for( i = points.begin(); i != points.end(); ++i )
	{
		const __m128 p = _mm_set_ps( 0, ( *i )[ 2 ], ( *i )[ 1 ], ( *i )[ 0 ] );
		float result = improvedNoise_impl< float >( p );
		if( show_result ) { std::cout << result << std::endl; }
	}
	std::cout << "finished sse2 noise...." << std::endl;
	std::cout << timer.elapsed() << std::endl;

	timer.restart();
	std::cout << std::endl;

	std::cout << "starting sse2 fbm noise...." << std::endl;
	for( i = points.begin(); i != points.end(); ++i )
	{
		const __m128 p = _mm_set_ps( 0, ( *i )[ 2 ], ( *i )[ 1 ], ( *i )[ 0 ] );
		float result = improvedNoiseFBM_impl< float >( p, 5, 2, 0.707f );
		if( show_result ) { std::cout << result << std::endl; }
	}
	std::cout << "finished sse2 fbm noise...." << std::endl;
	std::cout << timer.elapsed() << std::endl;

	timer.restart();
	std::cout << std::endl;

	std::cout << "3delight noise...." << std::endl;
	for( i = points.begin(); i != points.end(); ++i )
	{
		RtFloat noiseVal;
		RtInt success = RxNoise( 3, &( ( *i )[ 0 ] ), 1, &noiseVal );
	}
	std::cout << "finished 3delight noise...." << std::endl;
	std::cout << timer.elapsed() << std::endl;

	timer.restart();
	std::cout << std::endl;

	std::cout << "running noise equality test...." << std::endl;
	int num_different_points = 0;
	for( i = points.begin(); i != points.end(); ++i )
	{
		const __m128 p = _mm_set_ps( 0, ( *i )[ 2 ], ( *i )[ 1 ], ( *i )[ 0 ] );
		float no_sse2 = improvedNoise_impl< float >( *i );
		float using_sse2 = improvedNoise_impl< float >( p );
		if( no_sse2 != using_sse2 )
		{
			++num_different_points;
		}
	}
	std::cout << "finished noise equality test...." << std::endl;
	std::cout << "number of differing points = " << num_different_points << " out of " << NUM_POINTS << " difference = " << ( ( float ) num_different_points / ( float ) NUM_POINTS ) * 100.0f << "%" << std::endl;
	std::cout << timer.elapsed() << std::endl;

	timer.restart();
	std::cout << std::endl;

	std::cout << "running fbm noise equality test...." << std::endl;
	num_different_points = 0;
	for( i = points.begin(); i != points.end(); ++i )
	{
		const __m128 p = _mm_set_ps( 0, ( *i )[ 2 ], ( *i )[ 1 ], ( *i )[ 0 ] );
		float no_sse2 = improvedNoiseFBM_impl< float >( *i, 5, 2, 0.707f );
		float using_sse2 = improvedNoiseFBM_impl< float >( p, 5, 2, 0.707f );
		if( no_sse2 != using_sse2 )
		{
			++num_different_points;
		}
	}
	std::cout << "finished fbm noise equality test...." << std::endl;
	std::cout << "number of differing points = " << num_different_points << " out of " << NUM_POINTS << " difference = " << ( ( float ) num_different_points / ( float ) NUM_POINTS ) * 100.0f << "%" << std::endl;
	std::cout << timer.elapsed() << std::endl;
}